//This filter is Texte and seems to work correctly

//TODO: 
using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Exponential is an algorithm to exponentiate an image
    /// </summary>
    public class Exponential : BaseImageFilter
    {
        //The width and height of the output
        protected bool m_bConvertToGrayscale = true;

        protected float m_fExponent = -1.0f;
        //TODO: check if this can be deleted (inheritance)
        //protected float m_fScale = 1.0f;

        /// <summary>
        /// Initializes a new instance of the <see cref="Exponential"/> class.
        /// </summary>
        public Exponential()
            : this(true)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Exponential"/> class.
        /// </summary>
        /// <param name="_fExponent">The _f exponent.</param>
        /// <param name="_fOffset">The _f offset.</param>
        /// <param name="_fScale">The _f scale.</param>
        public Exponential(float _fExponent, float _fOffset, float _fScale)
            : this(_fExponent, _fOffset, _fScale, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Exponential"/> class.
        /// </summary>
        /// <param name="_fExponent">The _f exponent.</param>
        /// <param name="_fOffset">The _f offset.</param>
        /// <param name="_fScale">The _f scale.</param>
        /// <param name="_bConvertToGrayScale">if set to <c>true</c> [_b convert to gray scale].</param>
        public Exponential(float _fExponent, float _fOffset, float _fScale, bool _bConvertToGrayScale)
        {
            m_fExponent = _fExponent;
            m_fOffset = _fExponent;
            m_fScale = _fScale;
            m_bConvertToGrayscale = _bConvertToGrayScale;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Exponential"/> class.
        /// </summary>
        /// <param name="_bConvertToGrayScale">if set to <c>true</c> [_b convert to gray scale].</param>
        public Exponential(bool _bConvertToGrayScale)
        {
            m_bConvertToGrayscale = _bConvertToGrayScale;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Exponential"/> class.
        /// </summary>
        /// <param name="_exponential">The _exponential.</param>
        internal Exponential(Exponential _exponential)
        {
            this.m_bConvertToGrayscale = _exponential.m_bConvertToGrayscale;
            this.m_fExponent = _exponential.m_fExponent;
        }

        /// <summary>
        /// Gets or sets a value indicating whether [convert to gray scale].
        /// </summary>
        /// <value><c>true</c> if [convert to gray scale]; otherwise, <c>false</c>.</value>
        public bool ConvertToGrayScale
        {
            get { return m_bConvertToGrayscale; }
            set { m_bConvertToGrayscale = value; }
        }

        /// <summary>
        /// Gets or sets the exponent.
        /// </summary>
        /// <value>The exponent.</value>
        public float Exponent
        {
            get { return m_fExponent; }
            set { m_fExponent = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            ApplyExponential(_bitmap, _bitmap.Width, _bitmap.Height, m_fExponent, m_fScale, m_fOffset);
            return _bitmap;
        }

        /// <summary>
        ///exponential algorithm..
        ///*a) assume the image is grey level (hence RR=GG=BB)
        ///  b) use value 0x000000ff to get the BB value
        ///  c) apply the operation (eg exponentiate). 
        ///  d) return the result
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="nWidth">Width of the n.</param>
        /// <param name="nHeight">Height of the n.</param>
        /// <param name="dExponent">The d exponent.</param>
        /// <param name="fScaleval">The f scaleval.</param>
        /// <param name="fOffsetval">The f offsetval.</param>
        private void ApplyExponential(UnsafeBitmap _bitmap, int nWidth, int nHeight, double dExponent,
                     float fScaleval, float fOffsetval)
        {
            int nResult = 0;

            UnsafeBitmap bitmap = _bitmap;

            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    //Select required bits from image
                    Color color = bitmap.GetPixel(x, y);
                    int nValue = color.ToArgb();

                    if (m_bConvertToGrayscale)
                    {
                        nValue &= 0x000000ff;
                    }
                    else
                    {
                        int nR = GetColorExpoResult(color.R, dExponent, fScaleval, fOffsetval);
                        int nG = GetColorExpoResult(color.G, dExponent, fScaleval, fOffsetval); ;
                        int nB = GetColorExpoResult(color.B, dExponent, fScaleval, fOffsetval); ;
                        color = Color.FromArgb(nR, nG, nB);
                    }

                    //Perform operation
                    nResult = (int)(Math.Pow(dExponent, nValue));
                    nResult = (int)((nResult * fScaleval) + fOffsetval);
                    if (nResult > 255) nResult = 255;
                    if (nResult < 0) nResult = 0;

                    if (m_bConvertToGrayscale)
                    {
                        color = Color.FromArgb(((int)(uint)(0xFF << 24 | nResult << 16 | nResult << 8 | nResult))); //Original Code: (0xFF << 24 | nResult << 16 | nResult << 8 | nResult)));
                    }
                    bitmap.SetPixel(x, y, color);
                }
            }
        }

        /// <summary>
        /// Gets the color expo result.
        /// </summary>
        /// <param name="_nChannel">The _n channel.</param>
        /// <param name="expo">The expo.</param>
        /// <param name="fScaleVal">The f scale val.</param>
        /// <param name="fOffsetVal">The f offset val.</param>
        /// <returns></returns>
        private int GetColorExpoResult(int _nChannel, double expo, float fScaleVal, float fOffsetVal)
        {
            int nResult = (int)(Math.Pow(expo, _nChannel) * fScaleVal + fOffsetVal);
            if (nResult > 255) nResult = 255;
            if (nResult < 0) nResult = 0;
            return nResult;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Exponential(this);
        }
    }
}
  
